package tech.mhuang.pacebox.core.sugar;

import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.core.sugar.function.CheckedBiConsumer;
import tech.mhuang.pacebox.core.sugar.function.CheckedBiFunction;
import tech.mhuang.pacebox.core.sugar.function.CheckedConsumer;
import tech.mhuang.pacebox.core.sugar.function.CheckedFunction;
import tech.mhuang.pacebox.core.sugar.function.CheckedSupplier;

import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 封装受检异常为非受检函数
 * <p>参考:https://github.com/mizhoux/msugar</p>
 *
 * @author mhuang
 * @since 1.1.0
 */
public class Attempt {

    /**
     * 包装受检的 Function
     *
     * @param function 受检的 Function
     * @param <T>      t
     * @param <R>      r
     * @return 非受检的 Function
     */
    public static <T, R> Function<T, R> apply(CheckedFunction<T, R> function) {
        Objects.requireNonNull(function);

        return t -> {
            try {
                return function.apply(t);
            } catch (Throwable e) {
                throw new BusinessException(e);
            }
        };
    }

    /**
     * 包装受检的 Function，并自定义异常处理
     *
     * @param function 受检的 Function
     * @param handler  自定义异常处理
     * @param <T>      t
     * @param <R>      r
     * @return 非受检的 Function
     */
    public static <T, R> Function<T, R> apply(CheckedFunction<T, R> function, Function<Throwable, R> handler) {
        Objects.requireNonNull(function);
        Objects.requireNonNull(handler);

        return t -> {
            try {
                return function.apply(t);
            } catch (Throwable e) {
                return handler.apply(e);
            }
        };
    }


    /**
     * 包装受检的 BiFunction
     *
     * @param function 受检的 BiFunction
     * @param <T>      t
     * @param <U>      u
     * @param <R>      r
     * @return 非受检的 BiFunction
     */
    public static <T, U, R> BiFunction<T, U, R> apply(CheckedBiFunction<T, U, R> function) {
        Objects.requireNonNull(function);

        return (t, u) -> {
            try {
                return function.apply(t, u);
            } catch (Throwable e) {
                throw new BusinessException(e);
            }
        };
    }

    /**
     * 包装受检的 BiFunction，并自定义异常处理
     *
     * @param function 受检的 BiFunction
     * @param handler  自定义异常处理
     * @param <T>      t
     * @param <U>      u
     * @param <R>      r
     * @return 非受检的 BiFunction
     */
    public static <T, U, R> BiFunction<T, U, R> apply(CheckedBiFunction<T, U, R> function, Function<Throwable, R> handler) {
        Objects.requireNonNull(function);
        Objects.requireNonNull(handler);

        return (t, u) -> {
            try {
                return function.apply(t, u);
            } catch (Throwable e) {
                return handler.apply(e);
            }
        };
    }

    /**
     * 包装受检的 Consumer
     *
     * @param consumer 受检的 Consumer
     * @param <T>      t
     * @return 非受检的 Consumer
     */
    public static <T> Consumer<T> accept(CheckedConsumer<T> consumer) {
        Objects.requireNonNull(consumer);

        return t -> {
            try {
                consumer.accept(t);
            } catch (Throwable e) {
                throw new BusinessException(e);
            }
        };
    }

    /**
     * 包装受检的 Consumer，并自定义异常处理
     *
     * @param consumer 受检的 Consumer
     * @param handler  自定义异常处理
     * @param <T>      t
     * @return 非受检的 Consumer
     */
    public static <T> Consumer<T> accept(CheckedConsumer<T> consumer, Consumer<Throwable> handler) {
        Objects.requireNonNull(consumer);
        Objects.requireNonNull(handler);

        return t -> {
            try {
                consumer.accept(t);
            } catch (Throwable e) {
                handler.accept(e);
            }
        };
    }

    /**
     * 包装受检的 BiConsumer
     *
     * @param biConsumer 受检的 BiConsumer
     * @param <T>        t
     * @param <U>        u
     * @return 非受检的 BiConsumer
     */
    public static <T, U> BiConsumer<T, U> accept(CheckedBiConsumer<T, U> biConsumer) {
        Objects.requireNonNull(biConsumer);

        return (t, u) -> {
            try {
                biConsumer.accept(t, u);
            } catch (Throwable e) {
                throw new BusinessException(e);
            }
        };
    }

    /**
     * 包装受检的 BiConsumer，并自定义异常处理
     *
     * @param biConsumer 受检的 BiConsumer
     * @param handler    自定义异常处理
     * @param <T>        t
     * @param <U>        u
     * @return 非受检的 BiConsumer
     */
    public static <T, U> BiConsumer<T, U> accept(CheckedBiConsumer<T, U> biConsumer, Consumer<Throwable> handler) {
        Objects.requireNonNull(biConsumer);
        Objects.requireNonNull(handler);

        return (t, u) -> {
            try {
                biConsumer.accept(t, u);
            } catch (Throwable e) {
                handler.accept(e);
            }
        };
    }

    /**
     * 包装受检的 Supplier
     *
     * @param supplier 受检的 Supplier
     * @param <R>      r
     * @return 非受检的 Supplier
     */
    public static <R> Supplier<R> supply(CheckedSupplier<R> supplier) {
        Objects.requireNonNull(supplier);

        return () -> {
            try {
                return supplier.supply();
            } catch (Throwable e) {
                throw new BusinessException(e);
            }
        };
    }

    /**
     * 包装受检的 Supplier，并并自定义异常处理
     *
     * @param supplier 受检的 Supplier
     * @param handler  自定义异常处理
     * @param <R>      r
     * @return 非受检的 Supplier
     */
    public static <R> Supplier<R> supply(CheckedSupplier<R> supplier, Function<Throwable, R> handler) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(handler);

        return () -> {
            try {
                return supplier.supply();
            } catch (Throwable e) {
                return handler.apply(e);
            }
        };
    }

    /**
     * 请求调用应答
     *
     * @param request  请求
     * @param response 应答
     * @param <T>      请求得类型
     * @param <R>      应答得类型
     * @author mhuang
     * @since 1.1.7
     */
    public static <T, R> R invoke(Supplier<T> request, Function<T, R> response) {
        return response.apply(request.get());
    }

    /**
     * 请求调用应答
     *
     * @param request  请求
     * @param response 应答
     * @param handler  异常处理
     * @param <T>      请求得类型
     * @param <R>      应答得类型
     * @author mhuang
     * @since 1.1.7
     */
    public static <T, R> R invoke(Supplier<T> request, Function<T, R> response, Function<Throwable, R> handler) {
        try {
            return response.apply(request.get());
        } catch (Throwable e) {
            return handler.apply(e);
        }
    }
}
